package com.cskaoyan.yesterday.edition1;

public class Work {

    /**

     *
     * 既然是两个线程交替打印，那就是一个线程打印奇数，一个线程打印偶数

     * 奇数线程打印奇数，然后让被打印数字增1

     * 偶数线程打印偶数，然后让被打印数字增1

     * 直到打印到题目中数字的上界99

     */

    public static void main(String[] args) {

        //创建PrintNumber对象，该对象记录了被打印数字，同时，创建该对象时，指定打印数字的上界

        PrintNumber printNumber = new PrintNumber(99);
        OddTask oddTask = new OddTask(printNumber);
        EvenTask evenTask = new EvenTask(printNumber);


        new Thread(evenTask, "线程1").start();
        new Thread(oddTask, "线程2").start();
    }
}



/*

   定义一个类，封装被打印的数字

*/

class PrintNumber {
    private int i = 0;

    //指定被打印数字的上线，在题目中upBound的取值为99，只要打印到99即可

    private int upBound;
    public PrintNumber(int upBound) {
        this.upBound = upBound;
    }


 /*

     让被打印数字增1

  */
    public void add() {
        i++;
    }

 /*

     获取打印数字的上界

  */
    public int getUpBound() {
        return upBound;
    }



 /*

     获取被打印数字当前的值

  */

    public int value() {

        return i;

    }

}





/*

     打印奇数，和偶数线程的公共父类，打印的主要逻辑都在该类中

     子类只实现，具体的打印条件的判断即可，可以很大程度的复用代码

*/


/*

   打印奇数

*/

class OddTask implements Runnable {

    PrintNumber number;


    public OddTask(PrintNumber number) {
        this.number = number;
    }


    @Override
    public void run() {
        //如果还没打印到最大值，就接着循环打印
        while (number.value() <= number.getUpBound()) {
            synchronized (number) {
                // double check
                if (number.value() > number.getUpBound() ) {
                    //如果超出打印数字的上界，就退出循环不打印
                    break;
                }
                if (!shouldPrint()) {
                    //如果不满足打印条件，当前线程就不打印
                    try {
                        // 阻止自己
                        number.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    // 满足当前线程的打印条件
                    //打印数字的值
                    System.out.println(Thread.currentThread().getName() + " i = " + number.value());
                    //使被打印数字的值增1
                    number.add();
                    if (number.value() > number.getUpBound()) {
                        //被打印的数字的值，已经超过了了上界，即打印完了
                        System.out.println("打印完毕");
                    }
                    // 通知其他等待的打印线程，继续打印
                    number.notifyAll();
                }
            }
        }

    }


 /*
     打印奇数的线程，当number对象中，i的值为奇数时才打印
  */
    protected boolean shouldPrint() {
        return number.value() % 2 != 0;
    }
}



/*

   打印偶数

*/

class EvenTask implements Runnable {
    PrintNumber number;


    public EvenTask(PrintNumber number) {
        this.number = number;

    }

    @Override
    public void run() {

        //如果还没打印到最大值，就接着循环打印

        while (number.value() <= number.getUpBound()) {
            synchronized (number) {
                if (number.value() > number.getUpBound() ) {
                    //如果超出打印数字的上界，就退出循环不打印
                    break;
                }
                if (!shouldPrint()) {
                    //如果不满足打印条件，当前线程就不打印
                    try {
                        number.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    // 满足当前线程的打印条件
                    //打印数字的值
                    System.out.println(Thread.currentThread().getName() + " i = " + number.value());
                    //使被打印数字的值增1
                    number.add();
                    if (number.value() > number.getUpBound()) {
                        //被打印的数字的值，已经超过了了上界，即打印完了
                        System.out.println("打印完毕");
                    }
                    // 通知其他等待的打印线程，继续打印
                    number.notifyAll();
                }
            }
        }
    }

 /*
    打印偶数的线程，当number对象中，i的值为偶数时才打印
 */

    protected boolean shouldPrint() {
        return number.value() % 2 == 0;
    }

}
